"""
balanced_accuracy = 0.5 * (tp / (tp + fn) + tn / (tn + fp)) = 0.5 * （召回率 + 特异度）
"""
from keras.metrics import Recall, TrueNegatives, FalsePositives
from sklearn.metrics import balanced_accuracy_score


def get_data():
    """

    :return:
    """
    y_true = [0, 0, 1, 1, 0, 0, 1]
    y_pred = [0, 1, 0, 1, 0, 1, 0]
    return y_true, y_pred


def compute_ba(y_true, y_pred):
    """
    :param y_true:
    :param y_pred:
    :return:
    """
    tn = TrueNegatives()
    tn.update_state(y_true=y_true, y_pred=y_pred)
    tn_rs = tn.result().numpy()

    fp = FalsePositives()
    fp.update_state(y_true=y_true, y_pred=y_pred)
    fp_rs = fp.result().numpy()

    # 召回率
    recall = Recall()
    recall.update_state(y_true=y_true, y_pred=y_pred)
    recall_scores = recall.result().numpy()

    # 特异度
    specificity_scores = tn_rs / (tn_rs + fp_rs)

    # 召回率
    recall = tn_rs / (tn_rs + fp_rs)

    return 0.5 * (recall_scores + specificity_scores)


def run():
    """
    主程序
    :return:
    """
    y_true, y_pred = get_data()

    y_pred = [1 if ratio >= 0.5 else 0 for ratio in y_pred]

    # 自己计算
    ba = compute_ba(y_true=y_true, y_pred=y_pred)

    sklearn_ba_scores = balanced_accuracy_score(y_true=y_true, y_pred=y_pred)

    info = 'balanced_accuracy_score: my: {}, sklearn: {}'.\
        format(ba, sklearn_ba_scores)
    print(info)


if __name__ == '__main__':
    run()

